#include "Facility_Manager.h"

#ifndef HUB_H
#include "Hub.h"
#endif
#ifndef HUB_DEFINE_H
#include "Hub_Define.h"
#endif

#ifndef BELT_DEFINE_H
#include "Belt/belt_define.h"
#endif

#ifndef BASE_BELT_J
#include "Belt/base_belt.h"
#endif

#ifndef CUTTER_DEFINE_H
#include "Cutter/cutter_define.h"
#endif

#ifndef CUTTER_H
#include "Cutter/cutter.h"
#endif

#ifndef TRASH_H
#include "trash.h"
#endif

#ifndef MINER_DEFINE_H
#include "Miner/miner_define.h"
#endif

#ifndef MINER_H
#include "Miner/miner.h"
#endif


#ifndef ROTATOR_H
#include "rotator.h"
#endif

#ifndef BALANCER_H
#include "balancer.h"
#endif

const QString Facility_Manager::db_f_progress = "praogtreassD_f"; // Data progress_f
const int Facility_Manager::max_miner_progress = 4 - 1;        // max开采的升级进度
const int Facility_Manager::max_transport_progress =  4 - 1;   // max运输的升级进度
const int Facility_Manager::max_cutter_progress =   4 - 1;      // max裁剪的升级进度

Facility_Manager::Facility_Manager(Cargo_Manager *cargo_manager)
    :cargo_manager( cargo_manager )
{

}
// f_in 入口设备 被进入；f_out 出口设备 被拿走
void Facility_Manager::connetTwoFacility(Facility * f_in, int in_idx, Facility * f_out, int out_idx){
    f_in->pre_facility[in_idx] = {f_out,out_idx};   // f_in的in_idx口 的源头是 f_out的out_idx口
    f_out->next_facility[out_idx] = {f_in,in_idx}; // f_out的out_idx口 的出口是 f_in的in_idx口
}


void Facility_Manager::connnetFacilitys(Facility * f, std::unordered_set<Facility *>& fs){
    for(int in_idx = 0; in_idx < f->define->enters_num;++in_idx)
    {
        EnterGate&g_i = f->abs_enters[in_idx];
        for(auto other:fs){
            for(int out_idx = 0; out_idx < other->define->exits_num;++out_idx){
                ExitGate&g_o = other->abs_exits[out_idx];
                bool flag = g_i.can_take(g_o);
                if(flag){
                    connetTwoFacility(f,in_idx,other,out_idx);
                }
            }
        }
    }
    for(int out_idx = 0; out_idx < f->define->exits_num;++out_idx)
    {
        ExitGate&g_o = f->abs_exits[out_idx];
        for(auto other:fs){
            for(int in_idx = 0; in_idx < other->define->enters_num;++in_idx){
                EnterGate&g_i = other->abs_enters[in_idx];
                bool flag = g_o.can_goto(g_i);
                if(flag){
                    connetTwoFacility(other,in_idx,f,out_idx);
                }
            }
        }
    }
}

// 生成设备，不会生成图片，因为还不知道能不能放
Facility * Facility_Manager::generateFacilityWithTypeAndIdx
    (FacilityType f_type, int groupIdx,  FacilityDirection direction, Coordinate coordinate){
    std::string hash_id = FacilityDefine::fromTypeAndIdxToString(f_type,groupIdx);
    FacilityDefine * define = null;
    Facility * facility = null;
    if(facility_define_map.count(hash_id)){
        define = facility_define_map[hash_id];
    }
    else{ // first appear!
        switch(f_type){
        case FacilityType::HUB:
            define = new HubDefine(groupIdx);
            break;
        case FacilityType::BELT:
            define = new Belt_Define(transport_speed[transport_progress],groupIdx);
            break;
        case FacilityType::CUTTER:
            define = new Cutter_Define(cutter_speed[cutter_progress],groupIdx);
            break;
        case FacilityType::MINER:
            define = new Miner_Define(miner_speed[miner_progress],transport_speed[transport_progress],groupIdx);
            break;
        case FacilityType::TRASH:
            define = new Trash_Define();
            break;
        case FacilityType::BALANCER:
            define = new Balancer_Define(transport_speed[transport_progress],groupIdx);
            break;
        case FacilityType::PAINTER:

            break;
        case FacilityType::MIXER:

            break;
        case FacilityType::ROTATER:
            define = new Rotator_Define(transport_speed[transport_progress],groupIdx);
            break;
        case FacilityType::STACKER:

            // break;
        default:
            std::clog << ("others are not available!\n");
        }
        if(define)facility_define_map[hash_id] = define;
    }
    switch(f_type){
    case FacilityType::HUB:
        facility = new Hub((HubDefine*)define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::BELT:
        facility = new Base_Belt((Belt_Define*)define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::CUTTER:
        facility = new Cutter(define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::MINER:
        facility = new Miner(define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::TRASH:
        facility = new Trash(define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::BALANCER:
        facility = new Balancer(define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::PAINTER:

        break;
    case FacilityType::MIXER:

        break;
    case FacilityType::ROTATER:
        facility = new Rotator(define,direction,coordinate,cargo_manager);
        break;
    case FacilityType::STACKER:

        // break;
    default:
        std::clog << ("others are not available!\n");
    }
    if(facility){
        switch(f_type){
            case FacilityType::HUB:
                if(hub){delete facility; facility = null;}
                else{hub = (Hub*)facility;}
                break;
            case FacilityType::BELT:
                belt_facility.insert((Base_Belt*)facility);
                break;
            default:
                other_facility.insert(facility);
                break;
        }
    }
    return facility;
}

// 删除设备，会一同删除图片
void Facility_Manager:: deleteFacility(Facility * facility){
    if(!facility) return;
    switch(facility->define->facility_type){
    case FacilityType::HUB: // 不可以调用
        // if(hub){hub = null;}
        break;
    case FacilityType::BELT:
        belt_facility.erase((Base_Belt*)facility);
        break;
    default:
        other_facility.erase(facility);
    }
    // 删图
    if(facility->object_qt)
    {
        object_qt::removeObject(facility->object_qt);
        delete facility->object_qt;
        facility->object_qt = null;
    }
    delete facility;
}


void Facility_Manager::update(){
    hub->processCargo();
    for(auto &f:belt_facility){
        f->processCargo();
    }
    for(auto &f:other_facility){
        f->processCargo();
    }
}

void Facility_Manager::upgrate(int idx){
    switch(idx){
    case 0:
        this->miner_progress = std::min(this->max_miner_progress,this->miner_progress);
        for(auto &p:facility_define_map){
            auto &f = p.second;
            if(f && f->getFacilityType() == FacilityType::MINER){
                f->process_speed = this->miner_speed[this->miner_progress];
                f->interval = FacilityDefine::speedToInterval(f->process_speed);
            }
        }
        break;
    case 1:
        this->transport_progress = std::min(this->max_transport_progress,this->transport_progress);
        for(auto &p:facility_define_map){
            auto &f = p.second;
            if(f && (f->getFacilityType() == FacilityType::BELT
                      || f->getFacilityType() == FacilityType::BALANCER
                      || f->getFacilityType() == FacilityType::ROTATER)){
                f->process_speed = this->transport_speed[this->transport_progress];
                f->interval = FacilityDefine::speedToInterval(f->process_speed);
            }
        }
        break;
    case 2:
        this->cutter_progress = std::min(this->max_cutter_progress,this->cutter_progress);
        for(auto &p:facility_define_map){
            auto &f = p.second;
            if(f && (f->getFacilityType() == FacilityType::CUTTER)){
                f->process_speed = this->cutter_speed[this->cutter_progress];
                f->interval = FacilityDefine::speedToInterval(f->process_speed);
            }
        }
        break;
    default:
        break;
    }
}

void Facility_Manager::updateMinerTarget(Facility* miner,char t){
    if(miner->define->facility_type != FacilityType::MINER){return;}
    ((Miner*)miner)->setTarget(t);
}

void Facility_Manager::do_save(){
    QSettings setting(db_f_progress,QSettings::IniFormat);
    setting.setValue("transport",transport_progress);
    setting.setValue("cutter",cutter_progress);
    setting.setValue("miner",miner_progress);
}
void Facility_Manager::load_save(){
    QSettings setting(db_f_progress,QSettings::IniFormat);
    transport_progress = std::min(max_transport_progress,setting.value("transport",0).toInt());
    cutter_progress = std::min(max_cutter_progress,setting.value("cutter",0).toInt());
    miner_progress = std::min(max_miner_progress,setting.value("miner",0).toInt());
}

Facility_Manager::~Facility_Manager(){
    // hub
    if(hub){
        if(hub->object_qt)
        {
            object_qt::removeObject(hub->object_qt);
            delete hub->object_qt;
            hub->object_qt = null;
        }
        delete hub;
        hub = null;
    }
    // 其他
    for(auto &facility:other_facility){
        if(facility->object_qt)
        {
            object_qt::removeObject(facility->object_qt);
            delete facility->object_qt;
            facility->object_qt = null;
        }
        delete facility;
    }
    other_facility.clear();
    // 传送带
    for(auto &facility:belt_facility){
        if(facility->object_qt)
        {
            object_qt::removeObject(facility->object_qt);
            delete facility->object_qt;
            facility->object_qt = null;
        }
        delete facility;
    }
    belt_facility.clear();
    // 定义
    for(auto &p:facility_define_map){
        auto &fd = p.second;
        delete fd;
    }
}

